<?php

class DbMysqli extends Db
{
    public function __construct($config=''){
        if ( !extension_loaded('mysqli') ) {
            throw_exception(L('_NOT_SUPPERT_').':mysqli');
        }
        if(!empty($config)) {
            $this->config   =   $config;
        }
    }

    public function connect($config='',$linkNum=0) {
        if ( !isset($this->linkID[$linkNum]) ) {
            if(empty($config))  $config =   $this->config;
            $this->linkID[$linkNum] = new mysqli(
                                $config['hostname'],
                                $config['username'],
                                $config['password'],
                                $config['database'],
                                $config['hostport']);
            if (mysqli_connect_errno()) {
                throw_exception(mysqli_connect_error());
            }
            if($this->autoCommit){
                $this->linkID[$linkNum]->autocommit( true);
            }else {
                $this->linkID[$linkNum]->autocommit( false);
            }
            $this->dbVersion = $this->linkID[$linkNum]->server_version;
            if ($this->dbVersion >= "4.1") {
                $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'");
            }
            if($this->dbVersion >'5.0.1'){
                $this->linkID[$linkNum]->query("SET sql_mode=''");
            }
            $this->connected    =   true;
            if(1 != C('DB_DEPLOY_TYPE')) unset($this->config);
        }
        return $this->linkID[$linkNum];
    }

    public function free() {
        mysqli_free_result($this->queryID);
        $this->queryID = 0;
    }

    protected function _query($str='') {
        $this->initConnect(false);
        if ( !$this->_linkID ) return false;
        if ( $str != '' ) $this->queryStr = $str;
        if (!$this->autoCommit && $this->isMainIps($this->queryStr)) {
            $this->startTrans();
        }else {
            if ( $this->queryID ) {    $this->free();    }
        }
        $this->Q(1);
        $this->queryID = $this->_linkID->query($this->queryStr);
        $this->debug();
        if ( !$this->queryID ) {
            if ( $this->debug || C('DEBUG_MODE'))
                throw_exception($this->error());
            else
                return false;
        } else {
            $this->numRows  = $this->queryID->num_rows;
            $this->numCols    = $this->queryID->field_count;
            $this->resultSet    = $this->getAll();
            return $this->resultSet;
        }
    }

    protected function _execute($str='') {
        $this->initConnect(true);
        if ( !$this->_linkID ) return false;
        if ( $str != '' ) $this->queryStr = $str;
        if (!$this->autoCommit && $this->isMainIps($this->queryStr)) {
            $this->startTrans();
        }else {
            if ( $this->queryID ) {    $this->free();    }
        }
        $this->W(1);
        $result =   $this->_linkID->query($this->queryStr);
        $this->debug();
        if ( false === $result ) {
            if ( $this->debug || C('DEBUG_MODE'))
                throw_exception($this->error());
            else
                return false;
        } else {
            $this->numRows = $this->_linkID->affected_rows;
            $this->lastInsID = $this->_linkID->insert_id;
            return $this->numRows;
        }
    }

    public function startTrans() {
        $this->initConnect(true);
        if ($this->transTimes == 0) {
            $this->_linkID->autocommit(false);
        }
        $this->transTimes++;
        return ;
    }

    public function commit()
    {
        if ($this->transTimes > 0) {
            $result = $this->_linkID->commit();
            $this->_linkID->autocommit( true);
            $this->transTimes = 0;
            if(!$result){
                throw_exception($this->error());
                return false;
            }
        }
        return true;
    }

    public function rollback()
    {
        if ($this->transTimes > 0) {
            $result = $this->_linkID->rollback();
            $this->transTimes = 0;
            if(!$result){
                throw_exception($this->error());
                return false;
            }
        }
        return true;
    }

    public function next() {
        if ( !$this->queryID ) {
            throw_exception($this->error());
            return false;
        }
        if($this->resultType==DATA_TYPE_OBJ){
            $this->result = $this->queryID->fetch_object();
            $stat = is_object($this->result);
        }else{
            $this->result = $this->queryID->fetch_assoc();
            $stat = is_array($this->result);
        }
        return $stat;
    }

    public function getRow($sql = null,$seek=0) {
        if (!empty($sql)) $this->_query($sql);
        if ( !$this->queryID ) {
            throw_exception($this->error());
            return false;
        }
        if($this->numRows >0) {
            if($this->queryID->data_seek($seek)){
                if($this->resultType== DATA_TYPE_OBJ){
                    $result = $this->queryID->fetch_object();
                }else{
                    $result = $this->queryID->fetch_assoc();
                }
            }
            return $result;
        }else {
            return false;
        }
    }

    public function getAll($sql = null,$resultType=null) {
        if (!empty($sql)) $this->_query($sql);
        if ( !$this->queryID ) {
            throw_exception($this->error());
            return false;
        }
        $result = array();
        //$info   = $this->queryID->fetch_fields();
        if($this->numRows>0) {
            if(is_null($resultType)){ $resultType   =  $this->resultType ; }
            $fun    =   $resultType== DATA_TYPE_OBJ?'fetch_object':'fetch_assoc';
            for($i=0;$i<$this->numRows ;$i++ ){
                $result[$i] = $this->queryID->$fun();
            }
            $this->queryID->data_seek(0);
        }
        return $result;
    }

    function getFields($tableName) {
        $result =   $this->_query('SHOW COLUMNS FROM '.$tableName);
        $info   =   array();
        foreach ($result as $key => $val) {
            if(is_object($val)) {
                $val    =   get_object_vars($val);
            }
            $info[$val['Field']] = array(
                'name'    => $val['Field'],
                'type'    => $val['Type'],
                'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes
                'default' => $val['Default'],
                'primary' => (strtolower($val['Key']) == 'pri'),
                'autoInc' => (strtolower($val['Extra']) == 'auto_increment'),
            );
        }
        return $info;
    }

    function getTables($dbName='') {
        if(!empty($dbName)) {
           $sql    = 'SHOW TABLES FROM '.$dbName;
        }else{
           $sql    = 'SHOW TABLES ';
        }
        $result =   $this->_query($sql);
        $info   =   array();
        foreach ($result as $key => $val) {
            $info[$key] = current($val);
        }
        return $info;
    }

    function close() {
        if (!empty($this->queryID))
            $this->queryID->free_result();
        if (!$this->_linkID->close()){
            throw_exception($this->error());
        }
        $this->_linkID = 0;
    }

    function error() {
        $this->error = $this->_linkID->error;
        if($this->queryStr!=''){
            $this->error .= "\n ".L('_SQL_STATEMENT_')." : ".$this->queryStr;
        }
        return $this->error;
    }

    function escape_string($str) {
        if($this->_linkID) {
            return  $this->_linkID->real_escape_string($str);
        }else{
            return addslashes($str);
        }
    }

	public function limit($limit) {
        $limitStr    = '';
        if(!empty($limit)) {
            $limitStr .= ' LIMIT '.$limit.' ';
        }
        return $limitStr;
    }
}

?>